package packets;

import java.io.Serializable;
import java.security.PublicKey;

import packets.client.Login;
import packets.client.PublicKeyPair;
import packets.client.Registration;
import packets.server.Certificate;
import packets.server.UserDetails;
import packets.server.UserList;



import exceptions.InvalidPacketContentException;

/**
 * a general object that the server and client sends to communicate with each other
 * it has 2 fields - type and data.
 * type is to identify the {@link Packet}'s content
 * data is the {@link Packet}'s content
 */
public class Packet implements Serializable{

	private static final long serialVersionUID = 1L;

	public static final int PUBLIC_KEYS = 0;	//public keys packet
	public static final int STRING_MSG = 1;		//string reply - used for errors only
	public static final int CERTIFICATE = 2;	//certificate reply
	public static final int USERDETAILS = 3;	//userdetails replay
	public static final int USERLIST = 4;		//userlist reply
	public static final int REGISTRATION = 5;	//registration request
	public static final int LOGIN = 6;			//login request
	public static final int DELETE = 7;			//delete request
	public static final int LOGOUT = 8;			//logout request
	public static final int WHOSONLINE = 9;		//whosonline request
	public static final int ALLUSERS = 10;		//allusers request
	public static final int CHAT = 11;			//chat request
	public static final int DETAILS = 12;		//details request
	public static final int OK = 13;			//ok reply
	public static final int VERIFY = 14;		//verify Public key in CRL

	private int _type;
	protected Object _content;

	/**
	 * Creates an instance of Packet , that contains a {@link PublicKeyPair}
	 * @param content
	 */
	public Packet(PublicKeyPair content) {
		this._type = PUBLIC_KEYS;
		this._content = content;
	}
	/**
	 * Creates an instance of Packet , that contains a {@link PublicKey}
	 * @param content
	 */
	public Packet(PublicKey content) {
		this._type = VERIFY;
		this._content = content;
	}
	/**
	 * Creates an instance of Packet , that contains a {@link String}
	 * @param content
	 */
	public Packet(String content) {
		this._type = STRING_MSG;
		this._content = content;
	}
	/**
	 * Creates an instance of Packet , that contains a {@link Login}
	 * @param content
	 */
	public Packet(Login content){
		this._type = LOGIN;
		this._content = content;
	}
	/**
	 * Creates an instance of Packet , that contains a {@link Registration}
	 * @param content
	 */
	public Packet(Registration content){
		this._type = REGISTRATION;
		this._content = content;
	}
	/**
	 * Creates an instance of Packet , that contains a {@link Certificate}
	 * @param content
	 */
	public Packet(Certificate content) {
		this._type = CERTIFICATE;
		this._content = content;
	}
	/**
	 * Creates an instance of Packet , that contains a {@link UserDetails}
	 * @param content
	 */
	public Packet(UserDetails content) {
		this._type = USERDETAILS;
		this._content = content;
	}
	/**
	 * Creates an instance of Packet , that contains a {@link UserList}
	 * @param content
	 */
	public Packet(UserList content){
		this._type = USERLIST;
		this._content = content;
	}

	/**
	 * constructor for packets that their type is the message
	 * @param type the Packet's type
	 */
	protected Packet(int type){
		_type = type;
		_content = null;
	}

	/**
	 * constructor for chat/details packets
	 * @param type the Packet's type
	 * @param content Integer to store in the {@link Packet}
	 */
	protected Packet(int type, Integer content){
		_type = type;
		_content = content;
	}

	/**
	 *
	 * @return the {@link Packet}'s type
	 */
	public int getType() {
		return _type;
	}

	/**
	 *
	 * @return the {@link String} that the Packet stores
	 * @throws InvalidPacketContentException if the content is not a {@link String}
	 */
	public String getStringContent() throws InvalidPacketContentException{
		if (_type==STRING_MSG){
			return (String)_content;
		}else{
			throw new InvalidPacketContentException("Expected String packet, but got a different one");
		}
	}
	/**
	 *
	 * @return the {@link Registration} that the Packet stores
	 * @throws InvalidPacketContentException if the content is not a {@link Registration}
	 */
	public Registration getRegistrationContent() throws InvalidPacketContentException{
		if (_type==REGISTRATION){
			return (Registration)_content;
		}else{
			throw new InvalidPacketContentException("Expected registration packet, but got a different one");
		}
	}
	/**
	 *
	 * @return the {@link Login} that the Packet stores
	 * @throws InvalidPacketContentException if the content is not a {@link Login}
	 */
	public Login getLoginContent() throws InvalidPacketContentException{
		if (_type==LOGIN){
			return (Login)_content;
		}else{
			throw new InvalidPacketContentException("Expected login packet, but got a different one");
		}
	}
	/**
	 *
	 * @return the {@link PublicKeyPair} that the Packet stores
	 * @throws InvalidPacketContentException if the content is not a {@link PublicKeyPair}
	 */
	public PublicKeyPair getKeysContent() throws InvalidPacketContentException{
		if (_type==PUBLIC_KEYS){
			return (PublicKeyPair)_content;
		}else{
			throw new InvalidPacketContentException("Expected public keys packet, but got a different one");
		}
	}
	/**
	 *
	 * @return the {@link Certificate} that the Packet stores
	 * @throws InvalidPacketContentException if the content is not a {@link Certificate}
	 */
	public Certificate getCertificateContent() throws InvalidPacketContentException{
		if (_type==CERTIFICATE){
			return (Certificate)_content;
		}else{
			throw new InvalidPacketContentException("Expected certificate packet, but got a different one");
		}
	}

	/**
	 *
	 * @return the {@link UserDetails} that the Packet stores
	 * @throws InvalidPacketContentException if the content is not a {@link UserDetails}
	 */
	public UserDetails getDetailsContent() throws InvalidPacketContentException{
		if (_type==USERDETAILS){
			return (UserDetails)_content;
		}else{
			throw new InvalidPacketContentException("Expected details packet, but got a different one");
		}
	}

	/**
	 *
	 * @return the {@link UserList} that the Packet stores
	 * @throws InvalidPacketContentException if the content is not a {@link UserList}
	 */
	public UserList getUserListContent() throws InvalidPacketContentException{
		if (_type==USERLIST){
			return (UserList)_content;
		}else{
			throw new InvalidPacketContentException("Expected user list packet, but got a different one");
		}
	}

	/**
	 *
	 * @return the integer value that the Packet stores
	 * @throws InvalidPacketContentException if the content is not an Integer
	 */
	public int getIdContent(){
		return ((Integer)_content).intValue();
	}

	/**
	 * 
	 * @return the {@link PublicKey} value that the packet stores
	 * @throws InvalidPacketContentException if the content is not a {@link PublicKey}
	 */
	public PublicKey getKeyContent() throws InvalidPacketContentException {
		if (_type == VERIFY){
			return (PublicKey)_content;
		}else {
			throw new InvalidPacketContentException("Expected PublicKey packet, but got a different one");
		}
	}
}
